
#ifndef USER_APP
#define USER_APP

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbconfig.h"
#include "mbframe.h"
#include "mbutils.h"
/* ----------------------- Modbus 从站（Slave）模式配置 --------------------------*/
/*从站根据下面的配置 创建缓冲区保存自己各个寄存器的值 主机访问 直接把对应的值返回给主机*/
/* 离散输入（只读）：上报开关量状态（如传感器触发），起始地址0x00，地址范围0x00~0x04（共5个） */
#define S_DISCRETE_INPUT_START        0       
#define S_DISCRETE_INPUT_NDISCRETES   5      

/* 线圈（读写）：控制执行器（如继电器、风扇），起始地址0x01，地址范围0x01~0x05（共5个） */
#define S_COIL_START                  0       
#define S_COIL_NCOILS                 5      

/* 输入寄存器（只读）：上报模拟量数据（如温度、亮度），起始地址0x01，地址范围0x01~0x05（共5个16位寄存器） */
#define S_REG_INPUT_START             0       
#define S_REG_INPUT_NREGS             5      

/* 保持寄存器（读写）：存储控制参数/设备状态，起始地址0x00，地址范围0x00~0x04（共5个16位寄存器） */
#define S_REG_HOLDING_START           0       
#define S_REG_HOLDING_NREGS           5      



#ifdef USE_MODBUS_SLAVE
// 向外暴露4个缓冲区
#if S_DISCRETE_INPUT_NDISCRETES%8  // 若总数量不是8的倍数，需多1字节存储剩余bit
extern UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES / 8 + 1];
#else                               // 若总数量是8的倍数，字节数=总数量/8
extern UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES / 8];
#endif
#if S_COIL_NCOILS%8
extern UCHAR    ucSCoilBuf[S_COIL_NCOILS / 8 + 1];
#else
extern UCHAR    ucSCoilBuf[S_COIL_NCOILS / 8];
#endif
extern USHORT   usSRegInBuf[S_REG_INPUT_NREGS];  // 输入寄存器缓冲区：USHORT数组（1元素存1个16bit数据）
extern USHORT   usSRegHoldBuf[S_REG_HOLDING_NREGS];  // 保持寄存器缓冲区：USHORT数组（1元素存1个16bit数据）


// slave_addr:从机地址   reg_addr: 寄存器地址
// 线圈缓冲区 (用于控制外部设备的输出状态-->控制指示灯亮（1）或灭（0）。)
#define SLAVE_READ_COIL_DATA(reg_addr)  ( ucSCoilBuf[(reg_addr-S_COIL_START)/8] >> ((reg_addr-S_COIL_START)%8) & 0x01 )
#define SLAVE_UPDATE_1_TO_COIL(reg_addr)  ( ucSCoilBuf[(reg_addr-S_COIL_START)/8]|= (1<<((reg_addr-S_COIL_START)%8)))
#define SLAVE_UPDATE_0_TO_COIL(reg_addr)  ( ucSCoilBuf[(reg_addr-S_COIL_START)/8]&= (~(1<<((reg_addr-S_COIL_START)%8))))

// 离散输入缓冲区 (用于读取外部设备的开关状态-->读取指示灯亮（1）或灭（0）)
#define SLAVE_READ_DIS_DATA(reg_addr)  ( ucSDiscInBuf[(reg_addr-S_DISCRETE_INPUT_START)/8] >> ((reg_addr-S_DISCRETE_INPUT_START)%8) & 0x01 )
#define SLAVE_UPDATE_1_TO_DIS(reg_addr)  ( ucSDiscInBuf[(reg_addr-S_DISCRETE_INPUT_START)/8] |= (1 << ((reg_addr - S_DISCRETE_INPUT_START) % 8)) )
#define SLAVE_UPDATE_0_TO_DIS(reg_addr)  ( ucSDiscInBuf[(reg_addr-S_DISCRETE_INPUT_START)/8] &= ~(1 << ((reg_addr - S_DISCRETE_INPUT_START) % 8)) )

// 输入寄存器缓冲区  (读取外部设备的采集到的模拟量或数字量)
#define SLAVE_READ_INPUT_DATA(reg_addr)  ( usSRegInBuf[reg_addr-S_REG_INPUT_START])
#define SLAVE_UPDATE_INPUT_DATA(reg_addr,value)  ( usSRegInBuf[reg_addr-S_REG_INPUT_START]=value)

// 保持寄存器缓冲区 (读取存储设备的配置参数、设定值数据)
#define SLAVE_READ_HOLD_DATA(reg_addr)  ( usSRegHoldBuf[reg_addr-S_REG_HOLDING_START])
#define SLAVE_UPDATE_HOLD_DATA(reg_addr,value)  ( usSRegHoldBuf[reg_addr-S_REG_HOLDING_START]=value)

#endif


/* ----------------------- Modbus 主站（Master）模式配置 --------------------------*/
/*主站根据下面的配置 创建缓冲区保存各个从站 返回的各个寄存器的值 主机访问 直接把对应的值保存到缓冲区对应的位置*/
#define M_DISCRETE_INPUT_START        0       /* 主站离散输入缓冲区（只读）：对应从站0x01，地址范围0x01~0x05（共5个） */
#define M_DISCRETE_INPUT_NDISCRETES   5      

#define M_COIL_START                  0       /* 主站线圈缓冲区（读写）：控制从站线圈，对应从站0x01，地址范围0x01~0x05（共5个） */
#define M_COIL_NCOILS                 5      

#define M_REG_INPUT_START             0       /* 主站输入寄存器缓冲区（只读）：读取从站模拟量，对应从站0x01，地址范围0x01~0x05（5个16位） */
#define M_REG_INPUT_NREGS             5			

#define M_REG_HOLDING_START           0       /* 主站保持寄存器缓冲区（读写）：读写从站参数/状态，对应从站0x01，地址范围0x01~0x05（5个16位） */
#define M_REG_HOLDING_NREGS           5     

#ifdef USE_MODBUS_MASTER

// 向外暴露4个缓冲区
#if M_DISCRETE_INPUT_NDISCRETES%8
extern UCHAR    ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES / 8 + 1];
#else
extern UCHAR    ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES / 8];
#endif
#if  M_COIL_NCOILS%8
extern UCHAR    ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS / 8 + 1];
#else
extern UCHAR    ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS / 8];
#endif

extern USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];

extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];

// Modbus协议规定: 从机地址从0x01开始 寄存器地址从0x02开始
// FreeModbus采用二维数组的方式存储不用从机不同寄存器的数据 访问的时候 需要从机地址-1
// 使用宏的时候 输入标准的从机地址和寄存器地址就可以
// 线圈缓冲区读取 (用于控制外部设备的输出状态-->控制指示灯亮（1）或灭（0）。)
#define MASTER_READ_COIL_DATA(slave_addr, reg_addr)  ( ucMCoilBuf[slave_addr-1][(reg_addr-M_COIL_START)/8] >> ((reg_addr-M_COIL_START)%8) & 0x01 )

// 离散输入缓冲区读取(用于读取外部设备的开关状态-->读取指示灯亮（1）或灭（0）)
#define MASTER_READ_DIS_DATA(slave_addr, reg_addr)  ( ucMDiscInBuf[slave_addr-1][(reg_addr-M_DISCRETE_INPUT_START)/8] >> ((reg_addr-M_DISCRETE_INPUT_START)%8) & 0x01 )

// 输入寄存器缓冲区读取 (读取外部设备的采集到的模拟量或数字量)
#define MASTER_READ_INPUT_DATA(slave_addr, reg_addr)  ( usMRegInBuf[slave_addr-1][reg_addr-M_REG_INPUT_START] )

// 保持寄存器缓冲区读取(读取存储设备的配置参数、设定值数据)
#define MASTER_READ_HOLD_DATA(slave_addr, reg_addr)  ( usMRegHoldBuf[slave_addr-1][reg_addr-M_REG_HOLDING_START] )
#endif
#endif
